﻿using System;
using System.Collections.Generic;
using AlfarEngine.Data;
using AlfarEngine.Utilities;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace AlfarEngine.Components
{
    public class Sprite : AComponent
    {
        #region Variables

        protected ReferencedTexture mTexture;
        protected Rectangle? mSourceRect;
        protected Vector2? mOrigin;

        protected bool mShadowCaster;

        #endregion

        //-------------------------------------------

        #region Accessors

        /// <summary>
        /// Get the texture associated with this Sprite
        /// </summary>
        public ReferencedTexture texture { get { return mTexture; } set { setTexture(value); } }
        /// <summary>
        /// Get the source rectange, meaning the part of the texture drawn. If it's "null", then the entire texture is drawn
        /// </summary>
        public Rectangle? sourceRect { get { return mSourceRect; } set { setSourceRect(value); } }
        /// <summary>
        /// Get the center (in local coodinate) of this sprite
        /// </summary>
        public Vector2 center { get { return getCenter(); } }
        /// <summary>
        /// Get the origin of the sprite in local coordinate. 
        /// If null, mOrigin is set to the center of the sprite (if no sourceRect is set) or the center of sourceRect if set.
        /// </summary>
        public Vector2? origin { get { return mOrigin; } set { setOrigin(value); } }

        /// <summary>
        /// Define if this sprite cast shadow or not. Default is true
        /// </summary>
        public bool shadowCaster { get { return mShadowCaster; } set { mShadowCaster = value; } }

        #endregion

        //----------------------------------------------

        #region Methods

        public Sprite(GameObject pOwner)
            : base(pOwner)
        {
            mTexture = null;
            mSourceRect = null;
            mOrigin = null;
            mShadowCaster = true;

        }

        ~Sprite()
        {
            mTexture.Unload();
        }

        /// <summary>
        /// Set the texture to the designated Sprite
        /// </summary>
        /// <param name="pPath"></param>
        public void setTexture(string pPath)
        {
            mTexture = TextureDatabase.Load(pPath);

            if (mSourceRect == null)
            {
                setSourceRect(mTexture.texture.Bounds);

                //if no origin is set we set it to the new "center"
                if (mOrigin == null)
                    setOrigin(null);
            }
        }

        /// <summary>
        /// Set the texture to the given ReferencedTexture
        /// </summary>
        /// <param name="pTexture"></param>
        public void setTexture(ReferencedTexture pTexture)
        {
            pTexture.IncrementCount();
            mTexture = pTexture;

            if (mSourceRect == null)
            {
                setSourceRect(mTexture.texture.Bounds);

                //if no origin is set we set it to the new "center"
                if (mOrigin == null)
                    setOrigin(null);
            }
        }

        //******************

        public override void Update(Microsoft.Xna.Framework.GameTime pTime)
        {
            
        }

        //******************

        public override void Draw(GameTime pTime, Color pColor)
        {
            if (Engine.shadowPass && !mShadowCaster)
                return;

            Utilities.Debug.numberOfSpriteDraw++;

            Vector2 lPos = owner.position - new Vector2(Engine.currentViewport.X, Engine.currentViewport.Y);

            Engine.spriteBatch.Draw(mTexture.texture, lPos, mSourceRect, pColor, MathHelper.ToRadians(mOwner.rotation),
                                    origin.Value, Camera.mainCamera.invZoom, SpriteEffects.None, 0);
        }

        //****************

        public override void Serialize(System.IO.BinaryWriter pFile)
        {
            base.Serialize(pFile);

            pFile.Write(mTexture.path);

            pFile.Write(mSourceRect.Value.X);
            pFile.Write(mSourceRect.Value.Y);
            pFile.Write(mSourceRect.Value.Width);
            pFile.Write(mSourceRect.Value.Height);

            pFile.Write(mOrigin.Value.X);
            pFile.Write(mOrigin.Value.Y);

            pFile.Write(mShadowCaster);
        }

        public override void Deserialize(System.IO.BinaryReader pFile)
        {
            mTexture = TextureDatabase.Load(pFile.ReadString());

            mSourceRect = new Rectangle(pFile.ReadInt32(), pFile.ReadInt32(), pFile.ReadInt32(), pFile.ReadInt32());

            mOrigin = new Vector2(pFile.ReadSingle(), pFile.ReadSingle());
            mShadowCaster = pFile.ReadBoolean();
        }

        //**************************


        private Vector2 getCenter()
        {
            if(mSourceRect == null)
                return Vector2.Zero;

            return new Vector2(mSourceRect.Value.Width/2.0f, mSourceRect.Value.Height/2.0f);
        }

        private void setOrigin(Vector2? pValue)
        {
            if (pValue == null)
            {
                mOrigin = center;
                return;
            }

            mOrigin = pValue;

        }

        private void setSourceRect(Rectangle? pRect)
        {
            mSourceRect = pRect; 
            setOrigin(null);

            if (mSourceRect != null)
            {
                mOwner.localBounds = new Rectangle(-(int)origin.Value.X, -(int)origin.Value.Y, mSourceRect.Value.Width, mSourceRect.Value.Height);
            }
        }

        #endregion
    }
}
